package com.wngbms.netty.gatewaydemo.handler.bizhandler;

import com.wngbms.netty.gatewaydemo.filter.HttpRequestFilter;
import com.wngbms.netty.gatewaydemo.filter.HttpResponseFilter;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class OkhttpDoHttpInboundHandler extends BaseDoHttpInboundHandler {

    OkHttpClient okHttpClient = new OkHttpClient();

    public OkhttpDoHttpInboundHandler(List<String> backends,
                                      HttpResponseFilter httpResponseFilter) {
        super(backends, httpResponseFilter);
    }

    @Override
    public void handle(FullHttpRequest fullHttpRequest,
                       ChannelHandlerContext ctx,
                       HttpRequestFilter requestFilter) {

        String backendUrl = router.route(this.backendUrls);
        requestFilter.filter(fullHttpRequest, ctx);
        String url = backendUrl + fullHttpRequest.uri();
        proxyService.submit(() -> fetchGet(fullHttpRequest, ctx, url));
    }

    @Override
    public void fetchGet(FullHttpRequest request, ChannelHandlerContext ctx, String url) {
        HttpHeaders headers = request.headers();
        Map<String, String> headMap = headers.entries().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (t1, t2) -> t1));

        Request request1 = new Request.Builder()
                .url(url)
                .get()
                .headers(Headers.of(headMap))
                .build();

        Call call = okHttpClient.newCall(request1);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                call.cancel();
                log.error("exp", e);
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                handleResponse(request, ctx, response);
            }
        });
    }

    @Override
    public void handleResponse(FullHttpRequest fullHttpRequest,
                               ChannelHandlerContext ctx,
                               Object respObj) {
        FullHttpResponse response = null;
        Response resp = (Response) respObj;

        try {
            byte[] body = resp.body().bytes();
            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(body));
            response.headers().set("Content-Type", "application/json");
            response.headers().setInt("Content-Length",
                    Integer.parseInt(resp.headers().get("Content-Length")));

            if (httpResponseFilter != null) {
                httpResponseFilter.filter(response);
            }
        } catch (Exception e) {
            log.error("exp", e);
            response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NO_CONTENT);

            ctx.close();
        } finally {
            if (fullHttpRequest != null) {
                if (HttpUtil.isKeepAlive(fullHttpRequest)) {
                    ctx.writeAndFlush(response);
                } else {
                    ctx.writeAndFlush(response)
                            .addListener(ChannelFutureListener.CLOSE);
                }
            }
        }

    }

}
